import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { logger } from './tool/log';
import { AppModule } from './app/app.module';
import { TransformInterceptor } from './tool/transform.intercept'
import { HttpExceptionFilter } from './tool/http-exception.filter'
import { cors } from './tool/middle'

import {
  PipeTransform,
  ArgumentMetadata,
  HttpException,
  Injectable,
} from '@nestjs/common'
import { validate } from 'class-validator'
import { plainToClass } from 'class-transformer'
import * as _ from 'lodash'

@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value, metadata: ArgumentMetadata) {
    let request = value;
    const { metatype } = metadata;
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToClass(metatype, request);
    const errors = await validate(object);
    if (errors.length > 0) {
      let errorMessage = '';
      if (errors[0].contexts) {
        const key = Object.keys(errors[0].constraints).find(k => {
          return k in errors[0].contexts;
        });
        errorMessage = errors[0].constraints[key];
      } else {
        errorMessage = _.values(errors[0].constraints)[0];
      }
      const errorCode = 'contexts' in errors[0] ? _.values(errors[0].contexts)[0].errorCode : 599;
      throw new HttpException(errorMessage, errorCode);
    }
    return value;
  }

  private toValidate(metatype): boolean {
    const types = [String, Boolean, Number, Array, Object]
    return !types.find(type => metatype === type)
  }
}

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const options = new DocumentBuilder()
    .setTitle('Credit')
    .setDescription('The Credit API description')
    .setVersion('1.0')
    // .addTag('cats')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('api', app, document);
  // app.setGlobalPrefix('api/v1');
  app.use(logger);
  app.use(cors);
  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter());
  app.useGlobalInterceptors(new TransformInterceptor());
  // const { httpAdapter } = app.get(HttpAdapterHost);
  // app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));
  await app.listen(3000);
}
bootstrap();
